using System;
using System.Collections.Generic;
using Sce.PlayStation.Core;

namespace Nyanimals
{
	public class CInterpolator
	{
		private int animationIndex;
		private float currentTime;
		private bool playedOnce;
		private int currentFrame;
		private int lastFrame;

public	CInterpolator()  
		{ 
			animationIndex = -1;
			currentTime = 0.0f;
			playedOnce = false;
			currentFrame = 0;
			lastFrame = 0;
		}
	
		public int AnimationIndex
		{
			get { return animationIndex;}
			set { animationIndex = value;}
		}
		public float Time
		{
			get { return currentTime;}
			set { currentTime = value;}
		}
		public int CurrentFrame
		{
			get { return currentFrame;}
		}
		public int LastFrame
		{
			get { return lastFrame;}
		}
		public bool PlayedOnce
		{
			get { return playedOnce;}
		}
		public bool Process(List<Matrix4> tranBones, List<Matrix4> unTranBones, tFrameLimit limit, Matrix4 pParentMat)
		{
			CAnimation anim = CAnimationManager.Instance.GetAnimation(animationIndex);
			
			bool bStillPlaying = true;
		
			// ensure the current time doesnt fall below the starting frame's time
			if(currentTime < anim.Bones[0].KeyFrames[limit.StartFrame].KeyTime)
				currentTime = anim.Bones[0].KeyFrames[limit.StartFrame].KeyTime;
		
			// determine if the current time is on/past the ending frame's time
            float stopTime = anim.Bones[0].KeyFrames[limit.StopFrame].KeyTime;
            float strtTime = anim.Bones[0].KeyFrames[limit.StartFrame].KeyTime;
			if(currentTime > stopTime)
			{
				// the result will be determined if we are looping or not
				if(limit.Loop)
				{
					// make it the startign frames time
					currentTime = strtTime + (currentTime - stopTime);
				}
				else
				{
					// force it to be the ending frames time and mark we are done
					currentTime = stopTime;
					bStillPlaying = false;
				}
			}
		
            // start traversing from our root
            tBone rootBone = anim.RootBone;
            ProcessTraversal(rootBone, limit, unTranBones, tranBones);
			
			return bStillPlaying;
		}
		private void ProcessTraversal(tBone curBone, tFrameLimit limit, List<Matrix4> processedBones, List<Matrix4> tranBones)
        {
            int nCurFrame = 0;;
            int nNextFrame = 0;
            float tweenTime = 0.0f;
            bool bStay = false;
            CAnimation anim = CAnimationManager.Instance.GetAnimation(animationIndex);
            
            
            tKeyFrame curFrame;
            tKeyFrame nextFrame;
     
            // determine what frames we should interpolate between
            for(int keyframeIndex = limit.StartFrame; keyframeIndex <= limit.StopFrame; ++keyframeIndex)
            {
                // the next frame to interp
                if(keyframeIndex + 1 > limit.StopFrame)
                    nNextFrame = limit.StartFrame;
                else
                    nNextFrame = keyframeIndex + 1;
     
                curFrame  = curBone.KeyFrames[keyframeIndex];
                nextFrame = curBone.KeyFrames[nNextFrame];
     
                tweenTime = FMath.Abs(nextFrame.KeyTime - curFrame.KeyTime);
                if(tweenTime == 0.0f)
                {
                    bStay = true;
                }
                if(currentTime < curFrame.KeyTime + tweenTime)
                {
                    lastFrame = currentFrame;
                    currentFrame = keyframeIndex;//nNextFrame;
                    nCurFrame = keyframeIndex;
                    break;
                }
            }
            curFrame  = curBone.KeyFrames[nCurFrame];
            nextFrame = curBone.KeyFrames[nNextFrame];
     
            // interpolate each node
            Matrix4 currentPose;
            if(bStay || CInput.Instance.ButtonHeld(Sce.PlayStation.Core.Input.GamePadButtons.Circle))
            {
                currentPose = curFrame.LocalMatrix;
            }
            else
            {
                float Lam =  FMath.Abs(currentTime - curFrame.KeyTime) / tweenTime;
                
                currentPose = CMath.Interpolate(curFrame.LocalMatrix, nextFrame.LocalMatrix, Lam);
            }
     
            // parent if needed
            if(curBone.ParentIndex > -1)
            {
                Matrix4 pParentMat = processedBones[curBone.ParentIndex];
                currentPose = pParentMat * currentPose;
            }
            processedBones[curBone.MyIndex] = currentPose;
            
            // process each child
            foreach(int childIndex in curBone.ChildrenIndices)
            {
                tBone childBone = anim.Bones[childIndex];
                ProcessTraversal(childBone , limit, processedBones, tranBones);
            }
            
            // transform this bone into skin space
            tranBones[curBone.MyIndex] = currentPose * anim.BindPoseInverse[curBone.MyIndex];
        }

	}
}

